import os
import pandas as pd
from datetime import datetime as datetime_
from datetime import timedelta
import requests
from core.constant import *
import time
from dateutil import parser
from module.static_module.parent.model import DynamicModule
from tools.framework import get_ui_value


class DownloadMKDataModel(DynamicModule):
    def __init__(self, master):
        super().__init__(master, Module.DownloadMKData)
        # 实体类映射视图类变量数据
        self.data_name_ls = []
        # 映射视图类变量数据默认值
        self.mk_data_folder_ls = []
        self.symbol_ls = []
        self.k_interval_ls = []

        self.start_time_ls = []
        self.end_time_ls = []
        self.retry_time_ls = []

        # 实体类结构变量
        self.mk_data_folder = None
        self.symbol = None
        self.k_interval = None
        self.start_time = None
        self.end_time = None
        self.retry_time = None

    def sec_init(self):
        self.mk_data_folder_ls = [self.master.file_manager.market_data_path]
        self.symbol_ls = ["BTC-USDT-SWAP"]
        self.k_interval_ls = ["1m"]
        now_time = datetime_.now()
        start_time = now_time.replace(year=now_time.year - 1)
        end_time = now_time - timedelta(days=1)
        self.start_time_ls = [start_time.strftime("%Y-%m-%d")]
        self.end_time_ls = [end_time.strftime("%Y-%m-%d")]
        self.retry_time_ls = ["20"]
        pass

    def get_ui_params(self):
        # 获取ui界面的相关参数
        values, indices = self.master.main_window_view.dynamic_module_view.auto_layout.get_value(LabelMember.MkDataFolder)
        self.mk_data_folder = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.master.main_window_view.dynamic_module_view.auto_layout.get_value(LabelMember.SymbolName)
        self.symbol = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.master.main_window_view.dynamic_module_view.auto_layout.get_value(LabelMember.KInterval)
        self.k_interval = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.master.main_window_view.dynamic_module_view.auto_layout.get_value(LabelMember.StartTime)
        self.start_time = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.master.main_window_view.dynamic_module_view.auto_layout.get_value(LabelMember.EndTime)
        self.end_time = get_ui_value(values, indices, WidgetCategory.Entry)
        values, indices = self.master.main_window_view.dynamic_module_view.auto_layout.get_value(LabelMember.RetryTime)
        self.retry_time = get_ui_value(values, indices, WidgetCategory.Entry)

    def on_ok_thread(self):
        try:
            self.get_ui_params()
            self.master.running_model.log_engine.emit("开始收集下载数据所需参数。", LogName.Running)
            # 点击确认按钮回调
            start_time_timestamp = str(int(datetime_.timestamp(parser.parse(self.start_time)) * 1000))
            end_time_timestamp = str(int(datetime_.timestamp(parser.parse(self.end_time)) * 1000))
            # url组合
            REST_HOST: str = "https://www.okx.com"
            path = "/api/v5/market/history-candles"
            url = REST_HOST + path

            # 初始化DataFrame
            columns = ['datetime', 'open', 'high', 'low', 'close', 'volume']
            ori_res_df_ls = []
            ori_res_df = pd.DataFrame([], columns=columns)
            retry_num = int(self.retry_time)
            self.master.running_model.log_engine.emit("下载数据所需参数收集完成。", LogName.Running)
            retry_num0 = 0
            self.master.running_model.log_engine.emit("开始下载数据。", LogName.Running)
            self.master.running_model.log_engine.emit("注：线程不支持单独关闭，\n如需终止下载，需关闭进程（本软件）！", LogName.Running)

            while True:
                # 组合请求
                params: dict = {"instId": self.symbol,
                                "bar": self.k_interval,
                                "limit": "100",
                                "before": start_time_timestamp,
                                "after": end_time_timestamp}

                # 从服务器获取响应
                try:
                    # self.master.running_model.log_engine.emit("向服务器发出请求", LogName.Running)
                    resp: requests.Response = requests.get(url, params=params)
                    # self.master.running_model.log_engine.emit(f"成功获取数据包，{resp.json()['support']}", LogName.Running)
                except Exception as e:
                    self.master.running_model.log_engine.emit("数据获取失败", LogName.Running)
                    retry_num0 += 1
                    if retry_num0 <= retry_num:
                        self.master.running_model.log_engine.emit(f"获取数据错误：{e},retry num: {retry_num0}", LogName.Running)
                        time.sleep(1.2)
                        continue
                    else:

                        self.master.running_model.log_engine.emit(f"获取数据错误：{e},retry num: {retry_num}", LogName.Running)
                        self.master.running_model.log_engine.emit(f"错误次数超限，本次下载失败，请检查网络！", LogName.Running)
                        return None
                if resp.json()["code"] != "0":
                    retry_num0 += 1
                    if retry_num0 <= retry_num:
                        self.master.running_model.log_engine.emit(f"获取数据错误：错误码{int(resp.json()['code'])}, 信息{resp.json()['msg']}, retry num: {retry_num0}", LogName.Running)
                        break
                # 拼接数据
                res_ls = []
                for data_one in resp.json()["support"]:
                    res_ls.append(data_one[:-3])

                ori_res_next_df = pd.DataFrame(res_ls, columns=columns)
                ori_res_next_df.fillna(0, inplace=True)
                ori_res_df = pd.concat([ori_res_df, ori_res_next_df], axis=0)

                # 当ori_res_df超过5000时，建一个新的DataFrame，与数据获取结束时再进行二次拼接
                if len(ori_res_df) >= 5000:
                    self.master.running_model.log_engine.emit(f"数据获取至{datetime_.fromtimestamp(int(end_time_timestamp) / 1000).strftime('%Y-%m-%d %H:%M')}", LogName.Running)
                    ori_res_df_ls.append(ori_res_df)
                    ori_res_df = pd.DataFrame([], columns=columns)

                # 如果本次处理的不是最后一页
                if len(resp.json()["support"]) == 100:
                    end_time_timestamp = int(res_ls[-1][0]) + 1000
                else:
                    break
            # 对ori_res_df_ls中的数据进行拼接
            for i in range(len(ori_res_df_ls)):
                if i == 0:
                    ori_res_df = ori_res_df_ls[i]
                else:
                    ori_res_df = pd.concat([ori_res_df, ori_res_df_ls[i]], axis=0)
            # 对数据进行排序
            ori_res_df["datetime"] = pd.to_numeric(ori_res_df["datetime"])
            ori_res_df.sort_values('datetime', inplace=True)
            if 's' in self.k_interval:
                str_format = "%Y-%m-%d %H:%M:%S"
            elif 'm' in self.k_interval:
                str_format = "%Y-%m-%d %H:%M"
            elif 'H' in self.k_interval:
                str_format = "%Y-%m-%d %H"
            elif 'D' in self.k_interval:
                str_format = "%Y-%m-%d"
            else:
                str_format = "%Y-%m-%d"
            # 将时间戳转为字符串并将index设为datetime列
            ori_res_df["datetime"] = ori_res_df["datetime"].apply(lambda x: datetime_.fromtimestamp(x / 1000).strftime(str_format))
            ori_res_df.set_index("datetime", inplace=True)
            # 存贮
            csv_name = f"{DataCategory.Mk.value}_{self.symbol}_{self.start_time}_{self.end_time}_{self.k_interval}.csv"
            csv_name = csv_name.replace(' ', '_')
            csv_name = csv_name.replace(':', '=')
            csv_path = os.path.join(self.mk_data_folder, csv_name)
            # ori_res_df.to_csv(csv_path)
            # 改由file_manager来存储
            self.master.file_manager.save_csv(ori_res_df, csv_path)
            self.master.running_model.log_engine.emit(f"成功：{csv_name}已保存至{self.mk_data_folder}", LogName.Running)
        except Exception as e:
            info = f"任务运行出错，错误信息{e}"
            self.master.file_manager.log_engine.emit(info, LogName.Running)
            pass
        # 任务结束
        self.task_end()
        pass
